package com.mtconnect.common;

import com.mtconnect.dao.InitDB;
import com.mtconnect.exception.DAOException;
import com.mtconnect.model.Condition;
import com.mtconnect.model.Event;
import com.mtconnect.model.Sample;
import com.mtconnect.util.ResourceLoad;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.*;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static com.mtconnect.common.Constant.UNAVAILABLE;

/**
 * Created by Administrator on 2017/7/31.
 * 数据库表初始化用
 */
public class ValidateDB {

    private static final Logger LOGGER = LoggerFactory.getLogger(ValidateDB.class);

    private InitDB initDB = new InitDB();


    /**
     * system init create table
     */
    public void createTable() throws DAOException {
        List<String> table = null;
        Map<String, String> dataItem = ResourceLoad.TYPE_AND_CATEGORY;
        table = initDB.getAllTable();
        List<String> sequence = initDB.getAllSequence();
        sequence = getSequence(sequence);
        Set<String> set = dataItem.keySet();
        set.removeAll(table);
        for (String s : set) {
            if (Constant.SAMPLE.equalsIgnoreCase(dataItem.get(s))) {
                initDB.createSample(s, sequence.get(sequence.size() - 1));
            } else if (Constant.EVENT.equalsIgnoreCase(dataItem.get(s))) {
                initDB.createEvent(s, sequence.get(sequence.size() - 1));
            } else if (Constant.CONDITION.equalsIgnoreCase(dataItem.get(s))) {
                initDB.createCondition(s, sequence.get(sequence.size() - 1));
            }
        }

    }

    public List<String> getSequence(List<String> sequence) throws DAOException {
        if (sequence.isEmpty()) {
            initDB.createSequence("seq_1");
            sequence = initDB.getAllSequence();
        } else {
            Long num = initDB.getSequenceNum(sequence.get(sequence.size() - 1));
            if (null == num || num < 0) {//如果sequence已经超出了最大值或者出现了意外情况，那么就创建一个新的sequence
                String name = sequence.get(sequence.size() - 1);
                String var = name.substring(name.length() - 1);
                initDB.createSequence(Constant.SEQ_PREFIX + (Long.valueOf(var) + 1));
                sequence = initDB.getAllSequence();
            }
        }
        return sequence;
    }

    /**
     * 根据得到的元素对数据库表中的数据进行验证。如果没有数据则进行插入新数据操作，
     * 如果有，则根据每个元素的subType属性进行判断，如果此元素发生改变则进行更新。
     */
    public void validatorData() throws DAOException {
        try {
            List<Node> devices = ResourceLoad.DATA_ITEM_ELEMENT;
            for (Node node : devices) {
                Element e = (Element) node;
                String type = e.attributeValue("type");
                String dataItemID = e.attributeValue("id");
                String subType = e.attributeValue("subTypeBySample");
                String category = e.attributeValue("category");
                Integer countData = null;
                if (category.startsWith("C")) {
                    type = Constant.PRE_CONDITION + type;
                } else if (category.startsWith("E")) {
                    type = Constant.PRE_EVENT + type;
                } else {
                    type = Constant.PRE_SAMPLE + type;
                }
                countData = initDB.countData(type, subType, dataItemID);
                if (countData == null || countData <= 0) {//表示表中没有数据，或者没有这条数据。
                    List<String> allSequence = initDB.getAllSequence();
                    List<String> sequence = getSequence(allSequence);
                    Long num = initDB.getSequenceNum(sequence.get(sequence.size() - 1));
                    switch (category) {//判断那种类型的表，好做数据插入工作
                        case Constant.SAMPLE:
                            Sample sample = createSample(e, num, subType);
                            initDB.insertSample(type, sample);
                            break;
                        case Constant.EVENT:
                            Event event = createEven(e, num, subType);
                            initDB.insertEvent(type, event);
                            break;
                        case Constant.CONDITION:
                            Condition condition = createCondition(e, subType, num);
                            initDB.insertCondition(type, condition);
                            break;
                        default:
                            LOGGER.error("error category ===>{}", e.attributeValue("category"));
                    }
                }
            }
        } catch (DocumentException e) {
            LOGGER.warn("xml element parse failed", e);
        }
    }

    /**
     * 根据参数创建一个Condition对象
     *
     * @param e condition的xml元素
     * @param subType 0
     * @param num 当前的sequence值
     * @return 返回创建成功的Condition对象
     */
    private Condition createCondition(Element e, String subType, Long num) {
        Condition condition = new Condition();
        condition.setName(e.attributeValue("name"));
        condition.setSequence(num);
        condition.setTimestamp(new Timestamp(System.currentTimeMillis()));
        condition.setDataItemID(e.attributeValue("id"));
        condition.setSubType(subType);
        condition.setWarningType(UNAVAILABLE);
        return condition;
    }

    private Event createEven(Element e, Long num, String subType) {
        Event event = new Event();
        event.setSequence(num);
        event.setTimestamp(new Timestamp(System.currentTimeMillis()));
        event.setName(e.attributeValue("name"));
        event.setDataItemID(e.attributeValue("id"));
        event.setSubType(subType);
        String type = e.attributeValue("type");
        if ("ASSET_CHANGED".equalsIgnoreCase(type) || "ASSET_REMOVED".equalsIgnoreCase(type)) {
            event.setAssetType("initValue");
        }
        event.setValue(UNAVAILABLE);
        return event;
    }
    //<editor-fold desc="createEven method ,留后用">
    /*private Event createEven(Element e, Long num, String subTypeBySample, String Type) throws DocumentException {
        Event event = new Event();
        String name = e.attributeValue("name");
        if (null != name) {
            event.setName(name);
        }
        event.setSequence(num);
        event.setTimestamp(new Timestamp(System.currentTimeMillis()));
        event.setDataItemID(e.attributeValue("id"));
        if (null != subTypeBySample) {
            event.setSubType(subTypeBySample);
        }
        event.setAssetType(e.attributeValue("assetsType"));
        Document document = XMLUtil.asDoc(e);
        Node node1 = document.selectSingleNode("//Value");
        if (null != node1) {
            String val = node1.getText().toUpperCase();
            switch (Type.toUpperCase()) {//对于value列加约束，因为empress数据库目前不支持check约束，也不支持值enum
                case ACTUATOR_STATE:
                case AXIS_INTERLOCK:
                case CHUCK_INTERLOCK:
                case SPINDLE_INTERLOCK:
                    if (null == subTypeBySample) {
                        if (ACTIVE.equals(val) || INACTIVE.equals(val) || UNAVAILABLE.equals(val)) {
                            event.setValue(val);
                        } else {
                            throw new IllegalArgumentException("arguments is " + val);
                        }
                    }
                    break;
                case AVAILABILITY:
                    if (null == subTypeBySample) {
                        if (AVAILABLE.equals(val) || UNAVAILABLE.equals(val)) {
                            event.setValue(val);
                        } else {
                            throw new IllegalArgumentException("arguments is " + val);
                        }
                    }
                    break;
                case AXIS_COUPLING:
                    if (null == subTypeBySample) {
                        if (TANDEM.equals(val) || SYNCHRONOUS.equals(val) || MASTER.equals(val) || SLAVE.equals(val) || UNAVAILABLE.equals(val)) {
                            event.setValue(val);
                        } else {
                            throw new IllegalArgumentException("arguments is " + val);
                        }
                    }
                    break;
                case AXIS_STATE:
                    if (null == subTypeBySample) {
                        if (HOME.equals(val) || TRAVEL.equals(val) || PARKED.equals(val) || STOPPED.equals(val) || UNAVAILABLE.equals(val)) {
                            event.setValue(val);
                        } else {
                            throw new IllegalArgumentException("arguments is " + val);
                        }
                    }
                    break;
                case CHUCK_STATE:
                    if (subTypeBySample == null) {
                        if (OPEN.equals(val) || CLOSED.equals(val) || UNLATCHED.equals(val) || UNAVAILABLE.equals(val)) {
                            event.setValue(val);
                        } else {
                            throw new IllegalArgumentException("arguments is " + val);
                        }
                    }
                    break;
                case CONTROLLER_MODE:
                    if (subTypeBySample == null) {
                        if (AUTOMATIC.equals(val) || MANUAL.equals(val) || MANUAL_DATA_INPUT.equals(val) || SEMI_AUTOMATIC.equals(val) || EDIT.equals(val) || UNAVAILABLE.equals(val)) {
                            event.setValue(val);
                        } else {
                            throw new IllegalArgumentException("argument is " + val);
                        }
                    }
                    break;
                case DIRECTION:
                    if (ROTARY.equals(subTypeBySample.toUpperCase())) {
                        if (CLOCKWISE.equals(val) || COUNTER_CLOCKWISE.equals(val) || UNAVAILABLE.equals(val)) {
                            event.setValue(val);
                        } else {
                            throw new IllegalArgumentException("argument is " + val);
                        }
                    }
                    if (LINEAR.equals(subTypeBySample.toUpperCase())) {
                        if (POSITIVE.equals(val) || NEGATIVE.equals(val) || UNAVAILABLE.equals(val)) {
                            event.setValue(val);
                        } else {
                            throw new IllegalArgumentException("argument is " + val);
                        }
                    }
                    break;
                case DOOR_STATE:
                    if (subTypeBySample == null) {
                        if (OPEN.equals(val) || UNLATCHED.equals(val) || CLOSED.equals(val) || UNAVAILABLE.equals(val)) {
                            event.setValue(val);
                        } else {
                            throw new IllegalArgumentException("argument is " + val);
                        }
                    }
                    break;
                case END_OF_BAR:
                    if (subTypeBySample == null) {
                        if (YES.equals(val) || NO.equals(val) || UNAVAILABLE.equals(val)) {
                            event.setValue(val);
                        } else {
                            throw new IllegalArgumentException("argument is " + val);
                        }
                    }
                    break;
                case EMERGENCY_STOP:
                    if (subTypeBySample == null) {
                        if (ARMED.equals(val) || TRIGGERED.equals(val) || UNAVAILABLE.equals(val)) {
                            event.setValue(val);
                        } else {
                            throw new IllegalArgumentException("argument is " + val);
                        }
                    }
                    break;
                case EXECUTION:
                    if (subTypeBySample == null) {
                        switch (val) {
                            case READY:
                            case ACTIVE:
                            case INTERRUPTED:
                            case FEED_HOLD:
                            case STOPPED:
                            case OPTIONAL_STOP:
                            case PROGRAM_STOPPED:
                            case PROGRAM_COMPLETED:
                            case UNAVAILABLE:
                                event.setValue(val);
                                break;
                            default:
                                throw new IllegalArgumentException("argument is " + val);
                        }
                    }
                    break;
                case FUNCTIONAL_MODE:
                    if (subTypeBySample == null) {
                        switch (val) {
                            case PRODUCTION:
                            case SETUP:
                            case TEARDOWN:
                            case MAINTENANCE:
                            case PROCESS_DEVELOPMENT:
                            case UNAVAILABLE:
                                event.setValue(val);
                                break;
                            default:
                                throw new IllegalArgumentException("argument is " + val);
                        }
                    }
                    break;
                case INTERFACE_STATE:
                    if (subTypeBySample == null) {
                        if (ENABLED.equals(val) || DISABLED.equals(val) || UNAVAILABLE.equals(val)) {
                            event.setValue(val);
                        } else {
                            throw new IllegalArgumentException("argument is " + val);
                        }
                    }
                    break;
                case PART_COUNT:
                    if (subTypeBySample == null) {
                        Pattern pattern = Pattern.compile("^[\\+\\-]?[\\d]+(\\.[\\d]+)?$");
                        if (pattern.matcher(val).find()) {
                            event.setValue(val);
                        } else {
                            throw new IllegalArgumentException("argument is " + val);
                        }
                    }
                    break;
                case PATH_MODE:
                    if (subTypeBySample == null) {
                        if (INDEPENDENT.equals(val) || MASTER.equals(val) || SYNCHRONOUS.equals(val) || MIRROR.equals(val) || UNAVAILABLE.equals(val)) {
                            event.setValue(val);
                        } else {
                            throw new IllegalArgumentException("argument is " + val);
                        }
                    }
                    break;
                case POWER_STATE:
                    if (subTypeBySample == null) {
                        if (ON.equals(val) || OFF.equals(val) || UNAVAILABLE.equals(val)) {
                            event.setValue(val);
                        } else {
                            throw new IllegalArgumentException("argument is " + val);
                        }
                    }
                    break;
                case ROTARY_MODE:
                    if (subTypeBySample == null) {
                        if (SPINDLE.equals(val) || INDEX.equals(val) || CONTOUR.equals(val) || UNAVAILABLE.equals(val)) {
                            event.setValue(val);
                        } else {
                            throw new IllegalArgumentException("argument is " + val);
                        }
                    }
                    break;
                case MATERIAL_FEED:
                case MATERIAL_CHANGE:
                case MATERIAL_RETRACT:
                case MATERIAL_LOAD:
                case MATERIAL_UNLOAD:
                case PART_CHANGE:
                case OPEN_DOOR:
                case CLOSE_DOOR:
                case OPEN_CHUCK:
                case CLOSE_CHUCK:
                    if (subTypeBySample == null) {
                        switch (val) {
                            case NOT_READY:
                            case READY:
                            case ACTIVE:
                            case FAIL:
                            case COMPLETE:
                            case UNAVAILABLE:
                                event.setValue(val);
                                break;
                            default:
                                throw new IllegalArgumentException("argument is " + val);
                        }
                    }
                    break;
                default:
                    event.setValue(val);
            }
        }
        return event;
    }*/
    //</editor-fold>

    private Sample createSample(Element e, Long num, String subType) throws DocumentException {
        Sample sample = new Sample();
        sample.setName(e.attributeValue("name"));
        sample.setSequence(num);
        sample.setTimestamp(new Timestamp(System.currentTimeMillis()));
        sample.setDataItemID(e.attributeValue("id"));
        sample.setSubType(subType);
        sample.setSampleRate(e.attributeValue("sampleRate"));
        sample.setStatistic(e.attributeValue("statistic"));
        sample.setValue(UNAVAILABLE);
        return sample;
    }

    public void close() {
        initDB.close();
    }

}
